package main

import (
	"fmt"
	"os"
	"path"
	"path/filepath"
)

/*
FileInfo接口介绍
文件的信息包括文件名、文件大小、修改权限、修改时间等
*/
func main() {

	/*
		一. 文件路径
			• 绝对路径（absolute），例如D:/go/ch09/picture/soldier.jpg；
			• 相对路径（relative）是相对于当前的工程，“.”表示当前目录，“..”表示上一层。假如工程所在路径为D:/go/ch09/，
			  那么该文件的相对路径就是./picture/soldier.jpg
	*/
	filePath := "C:/Users/Steven/Desktop/person/git/gostudy/README.md"
	printFileInfo(filePath)
	filePath = "./README.md"
	printFileInfo(filePath)

	/*
		二. 文件路径判断
	*/
	filePath = "C:/Users/Steven/Desktop/person/git/gostudy/README.md"
	path2 := "./README.md"
	// filepath.IsAbs() 判断是否是绝对路径
	fmt.Println("是否是绝对路径：", filepath.IsAbs(filePath))
	fmt.Println("是否是绝对路径：", filepath.IsAbs(path2))
	// filepath.Rel() 获取[绝对路径]对于指定路径的相对路径
	fmt.Println(filepath.Rel("C:/Users/Steven", filePath))
	// filepath.Abs() 获取绝对路径
	fmt.Println(filepath.Abs(filePath))
	fmt.Println(filepath.Abs(path2))
	// path.Join() 拼接路径
	fmt.Println(path.Join(filePath, ".."))

	/*
		三.创建目录
			TIPS：创建目录时，如果目录存在，则创建失败
	*/
	fileName := "./test"
	// os.MKdir()：仅创建一层目录
	err := os.Mkdir(fileName, os.ModePerm)
	if err != nil {
		fmt.Println("error：", err.Error())
	}
	// os.MKdirAll()：创建多层目录
	fileName = "test2/test22/test222/xyz"
	err = os.MkdirAll(fileName, os.ModePerm)
	if err != nil {
		fmt.Println("error：", err.Error())
	}

	/*
		四. 创建文件
			TIPS：如果文件存在，会将其覆盖
	*/
	// os.Create()：该函数本质上是在调用os.OpenFile()函数
	fileName2 := "./abc.txt"
	create, err := os.Create(fileName2)
	if err != nil {
		fmt.Println("error：", err.Error())
	} else {
		fmt.Printf("%s 创建成功! %v \n", fileName2, create)
	}
	create.Close()

	/*
		五. 打开和关闭文件
			让当前的程序和指定的文件建立一个链接
	*/
	// os.Open()：该函数本质上是在调用os.OpenFile()函数
	open, err := os.Open(fileName2)
	if err != nil {
		fmt.Println("error：", err.Error())
	} else {
		fmt.Printf("%s 打开成功！%v \n", fileName2, open)
	}
	// 已读写方式打开，如果文件不存在就创建
	// TIPS：OpenFile(name string, flag int, perm FileMode)函数 参数介绍：
	// 		 · filename，文件名称；
	//		 · mode，文件的打开方式。可同时使用多个方式，用“|”分开。使用os.O_ 开始的参数来选择；
	//       · perm，文件的权限。文件不存在时创建文件，需要指定权限
	fileName3 := "./txt4.txt"
	file, err := os.OpenFile(fileName3, os.O_RDWR|os.O_CREATE, os.ModePerm)
	if err != nil {
		fmt.Println("error：", err.Error())
	} else {
		fmt.Printf("%s 打开成功！%v \n", fileName3, file)
	}

	// file.Close()：关闭文件。程序和文件之间的链接断开，通常与打开文件配对使用
	err = open.Close()
	if err != nil {
		fmt.Println("error：", err.Error())
	}
	file.Close()

	/*
		六. 删除文件。删除文件有两种方法：
			1. 	os.Remove()：删除已经命名的文件或【空目录】
			2.  os.RemoveAll()：移除指定路径包括他的任何子节点
	*/
	err = os.Remove("./abc.txt")
	if err != nil {
		fmt.Println("error：", err.Error())
	}
	os.Remove("./txt4.txt")
	os.RemoveAll("./test")
	os.RemoveAll("./test2")
}

func printFileInfo(path string) {

	stat, err := os.Stat(path)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	fmt.Printf("数据类型为：%T \n", stat)
	fmt.Println("文件名：", stat.Name())
	fmt.Println("是否为目录：", stat.IsDir())
	fmt.Println("文件大小：", stat.Size(), "字节")
	// TIPS：文件的权限打印出来一共10个字符。文件有3种基本权限：r（read，读权限）、w（write，写权限）、x（execute，执行权限）
	fmt.Println("文件权限：", stat.Mode())
	fmt.Println("最后修改时间：", stat.ModTime())
}
